/*	Copyright 2007 - Xavier Baro (xbaro@cvc.uab.cat)

	This file is part of eapmlib.

    Eapmlib is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or any 
	later version.

    Eapmlib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "UnivariateProbModel.h"
#include <time.h>

Evolutive::CUnivariateProbModel::CUnivariateProbModel() : CProbModel(),m_ProbDist(NULL),m_LR(0)
{	
	// Set the default parameters
	m_LR=0.1;
}

Evolutive::CUnivariateProbModel::~CUnivariateProbModel()
{
	// Release the remaining memory
	if(m_ProbDist)
		delete[] m_ProbDist;
}

bool Evolutive::CUnivariateProbModel::IsStatic(double Tolerance)
{
	register int i;
	double InvTolerance=1.0-Tolerance;

	/* If all the probabilities are lower than the Tolerance or 
	higher than 1-Tolerance the model is considered still.*/
	for(i=0;i<m_NumVars;i++)
	{
		if(m_ProbDist[i]>=Tolerance && m_ProbDist[i]<=InvTolerance)
			return false;
	}

	return true;
}

void Evolutive::CUnivariateProbModel::NewPopulation(Evolutive::CPopulation &Population,CODING_METHOD ModelCode,CEvaluator *Evaluator)
{
	register int i;
	int PopSize;

	// Retrieve the number of individuals
	PopSize=Population.GetPopulationUpdSize();

	// Initialize the random generator
	srand( (unsigned)time( NULL ) );

	// Use the probability distribution to generate the individuals
	for(i=0;i<PopSize;i++)
	{		
		// Check the existence of an evaluation function to verify the new individuals
		if(Evaluator)
		{
			// All generated individuals must be valid individuals
			do
			{
				Population[i].Generate(m_ProbDist);
			} while(!Evaluator->IsValid(&(Population[i])));
		}
		else
		{
			Population[i].Generate(m_ProbDist);
		}
	}
}

void Evolutive::CUnivariateProbModel::Update(Evolutive::CChromosome &C)
{
	register int i;

	double InvLR=1.0-m_LR;
	unsigned char *pC=NULL;

	//! Point to the chromosome data
	pC=C.GetBitStringPtr();

	//! Modify each variable using the given individual
	for(i=0;i<m_NumVars;i++)
	{
		m_ProbDist[i]=m_ProbDist[i]*InvLR+m_LR*pC[i];
	}
}

void Evolutive::CUnivariateProbModel::Estimate(int NumIndividuals,Evolutive::CPopulation &Population)
{
	register int i,j;
	unsigned char *pC=NULL;

	//! Initialize the probability distribution to 0
	memset(m_ProbDist,0,sizeof(double)*m_NumVars);

	//! Use the best individuals
	for(j=0;j<NumIndividuals;j++)
	{			
		//! Point to the chromosome data
		pC=Population.GetSortedChromosomePtr(j)->GetBitStringPtr();

		//! Modify each variable using the given individual
		for(i=0;i<m_NumVars;i++)
		{	
			m_ProbDist[i]+=pC[i];
		}
	}

	//! Obtain the probability
	for(i=0;i<m_NumVars;i++)
	{	
		m_ProbDist[i]/=NumIndividuals;
	}
}

void Evolutive::CUnivariateProbModel::InitializeModel(int NumVars,Evolutive::CPopulation &Population)
{
	register int i;
	//! Call the base constructor
	CProbModel::InitializeModel(NumVars,Population);

	//! Remove old data
	if(m_ProbDist)
		delete[] m_ProbDist;

	//! Allocate the new model struct
	m_ProbDist=new double[m_NumVars];

	//! Assign a random probability to all values
	for(i=0;i<m_NumVars;i++)
		m_ProbDist[i]=0.5;
}

void Evolutive::CUnivariateProbModel::SetLR(double LR)
{
	m_LR=LR;
}
